package cn.lili.modules.order.order.entity.dos;

import cn.lili.common.exception.ServiceException;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
import cn.lili.modules.order.order.entity.dto.CurrentRefundPriceDTO;
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
import cn.lili.mybatis.model.BaseEntity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serial;
import java.util.Date;

/**
 * 商家订单流水
 *
 * @author Chopper
 * @since 2020/11/17 7:31 下午
 */
@Data
@TableName("li_order_item_flow")
@ApiModel(value = "子订单流水")
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class OrderItemFlow extends BaseEntity {

    @Serial
    private static final long serialVersionUID = -5998757398902747939L;

    @ApiModelProperty(value = "流水编号")
    private String sn;

    @ApiModelProperty(value = "流水编号")
    private String orderFlowSn;

    @ApiModelProperty(value = "订单sn")
    private String orderSn;

    @ApiModelProperty(value = "子订单sn")
    private String orderItemSn;


    @ApiModelProperty(value = "是否支付")
    private Boolean isPay;

    @ApiModelProperty(value = "是否全部退款，true为全部退款")
    private Boolean fullRefund;

    @ApiModelProperty(value = "商品ID")
    private String goodsId;

    @ApiModelProperty(value = "商品名称")
    private String goodsName;

    @ApiModelProperty(value = "货品ID")
    private String skuId;

    @ApiModelProperty(value = "图片")
    private String image;

    @ApiModelProperty(value = "分类ID")
    private String categoryId;

    @ApiModelProperty(value = "规格json")
    private String specs;

    @ApiModelProperty(value = "店铺名称")
    private String storeName;

    @ApiModelProperty(value = "店铺ID")
    private String storeId;

    @ApiModelProperty(value = "供应商名称")
    private String supplierName;

    @ApiModelProperty(value = "供应商ID")
    private String supplierId;

    @ApiModelProperty(value = "销售量")
    private Integer num;

    @CreatedDate
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    @ApiModelProperty(value = "创建时间", hidden = true)
    private Date createTime;


    @ApiModelProperty(value = "流水金额")
    private Double flowPrice;

    @ApiModelProperty(value = "退款金额")
    private Double refundPrice;


    //============================================profitsharing================================================

    @ApiModelProperty(value = "店铺结算金额")
    private Double sellerSettlementPrice = 0D;

    @ApiModelProperty(value = "供应商结算金额")
    private Double supplierSettlementPrice = 0D;

    @ApiModelProperty(value = "分销佣金")
    private Double distributionSettlementPrice = 0D;

    @ApiModelProperty(value = "平台盈利金额=实际支付金额(flowPrice)-商家结算金额(sellerSettlementPrice)-供应商结算金额(supplierSettlementPrice)")
    private Double platformSettlementPrice = 0D;


    //============================================退款金额部分================================================

    @ApiModelProperty(value = "退还金额")
    private Double sellerRefundPrice = 0D;

    @ApiModelProperty(value = "供应商退还金额")
    private Double supplierRefundPrice = 0D;

    @ApiModelProperty(value = "分销退还佣金")
    private Double distributionRefundPrice = 0D;

    @ApiModelProperty(value = "平台退还金额")
    private Double platformRefundPrice = 0D;

    @ApiModelProperty(value = "用户ID")
    private String userId;

    @ApiModelProperty(value = "分销商标识")
    private String distributionId;

    @ApiModelProperty(value = "分销商标识")
    private String distributionName;

    /**
     * 构造方法
     *
     * @param orderFlow 订单 流水
     * @param item      订单项
     */
    public OrderItemFlow(OrderFlow orderFlow, OrderItem item) {


        BeanUtil.copyProperties(orderFlow, this);
        BeanUtil.copyProperties(item, this);


        this.setId(null);

        this.setUserId(orderFlow.getMemberId());
        // 子订单项
        this.setOrderItemSn(item.getSn());
        this.setOrderSn(item.getOrderSn());

        //入账
        this.setSn(SnowFlake.createStr("OIF"));
        this.setOrderFlowSn(orderFlow.getSn());

        //去掉orderitem的时间。
        this.setCreateTime(null);

        this.setRefundPrice(0D);
        this.setFullRefund(false);

        //获取金额详情
        PriceDetailDTO priceDetailDTO = PriceDetailDTO.getModel(item.getPriceDetail());

        if (priceDetailDTO != null) {
            this.setFlowPrice(priceDetailDTO.getFlowPrice());
            this.setSupplierSettlementPrice(priceDetailDTO.getSupplierSettlementPrice());
            this.setSellerSettlementPrice(priceDetailDTO.getSellerSettlementPrice());
            this.setDistributionSettlementPrice(priceDetailDTO.getDistributorSettlementPrice());
            this.setPlatformSettlementPrice(priceDetailDTO.getPlatformSettlementPrice());
        } else {
            throw new ServiceException("订单流水金额详情为空");
        }
    }

    /**
     * 退款
     *
     * @param afterSale 退款流水
     */
    public CurrentRefundPriceDTO refund(AfterSale afterSale) {

        //汇总退款金额
        CurrentRefundPriceDTO currentRefundPriceDTO = new CurrentRefundPriceDTO();

        //如果全额退款，则直接全部退款
        if (afterSale.getFlowPrice().equals(this.flowPrice)) {
            //退款金额等于：分账金额-已退款金额
            currentRefundPriceDTO.setSupplierRefundPrice(CurrencyUtil.sub(this.supplierSettlementPrice, this.supplierRefundPrice));
            currentRefundPriceDTO.setSellerRefundPrice(CurrencyUtil.sub(this.sellerSettlementPrice, this.sellerRefundPrice));
            currentRefundPriceDTO.setDistributionRefundPrice(CurrencyUtil.sub(this.distributionSettlementPrice, this.distributionRefundPrice));
            currentRefundPriceDTO.setPlatformRefundPrice(CurrencyUtil.sub(this.platformSettlementPrice, this.platformRefundPrice));

            //将退款金额赋值到当前流水信息
            this.setSupplierRefundPrice(this.supplierSettlementPrice);
            this.setSellerRefundPrice(this.sellerSettlementPrice);
            this.setDistributionRefundPrice(this.distributionSettlementPrice);
            this.setPlatformRefundPrice(this.platformSettlementPrice);

        } else {

            //汇总当前总退款额 占比
            this.refundPrice = CurrencyUtil.add(this.getRefundPrice(), afterSale.getApplyRefundPrice());


            //总退款比例 = 退款金额/流水金额
            Double refundRatio = CurrencyUtil.div(this.refundPrice, this.getFlowPrice(), 5);

            //退款金额计算

            // 总结算金额*总退款比例 = 应该退款金额
            //应退款金额-已退款金额=本次退款金额
            currentRefundPriceDTO.setSupplierRefundPrice(
                    CurrencyUtil.sub(CurrencyUtil.mul(this.supplierSettlementPrice, refundRatio), supplierRefundPrice)
            );

            currentRefundPriceDTO.setSellerRefundPrice(
                    CurrencyUtil.sub(CurrencyUtil.mul(this.sellerSettlementPrice, refundRatio), sellerRefundPrice)
            );

            currentRefundPriceDTO.setDistributionRefundPrice(
                    CurrencyUtil.sub(CurrencyUtil.mul(this.distributionSettlementPrice, refundRatio), distributionRefundPrice)
            );

            currentRefundPriceDTO.setPlatformRefundPrice(
                    CurrencyUtil.sub(CurrencyUtil.mul(this.platformSettlementPrice, refundRatio), platformRefundPrice)
            );

            //对售后金额断言 累加
            assertPrice(afterSale.getFlowPrice(), currentRefundPriceDTO);

//            PS:直接计算退款金额会有问题，这里应该汇总计算，计算所有人的退款总额占比，再计算每个人的占比金额

//            重现问题：购买a商品3个，每个30元，商品平台分润百分之9，然后一个一个退款，最终会看到平台结算-0.63 店铺结算 0.63 不符合预期

//            //退款比例 = 退款金额/流水金额
//            Double refundRatio = CurrencyUtil.div(afterSale.getApplyRefundPrice(), this.getFlowPrice());
//
//            //退款金额计算
//
//            // 结算金额*退款比例 = 应该退款金额
//            currentRefundPriceDTO.setSupplierRefundPrice(
//                    CurrencyUtil.mul(this.supplierSettlementPrice, refundRatio)
//            );
//
//            currentRefundPriceDTO.setSellerRefundPrice(
//                    CurrencyUtil.mul(this.sellerSettlementPrice, refundRatio)
//            );
//
//            currentRefundPriceDTO.setDistributionRefundPrice(
//                    CurrencyUtil.mul(this.distributionSettlementPrice, refundRatio)
//            );
//
//            currentRefundPriceDTO.setPlatformRefundPrice(
//                    CurrencyUtil.mul(this.platformSettlementPrice, refundRatio)
//            );
//
//            assertPrice(afterSale.getFlowPrice(), currentRefundPriceDTO);
//
//            //将退款金额赋值到当前流水信息
//            this.setSupplierRefundPrice(CurrencyUtil.add(this.supplierRefundPrice, currentRefundPriceDTO.getSupplierRefundPrice()));
//            this.setSellerRefundPrice(CurrencyUtil.add(this.sellerRefundPrice, currentRefundPriceDTO.getSellerRefundPrice()));
//            this.setDistributionRefundPrice(CurrencyUtil.add(this.distributionRefundPrice, currentRefundPriceDTO.getDistributionRefundPrice()));
//            this.setPlatformRefundPrice(CurrencyUtil.add(this.platformRefundPrice, currentRefundPriceDTO.getPlatformRefundPrice()));


        }

        return currentRefundPriceDTO;
    }

    /**
     * 兜底测略，断言以下退款流水金额是否等于 每个角色退款金额总和
     * <p>
     * ps:ruguo
     *
     * @param flowPrice 退款流水金额
     */
    private void assertPrice(Double flowPrice, CurrentRefundPriceDTO currentRefundPriceDTO) {
        Double refundTotal = currentRefundPriceDTO.getTotalRefundPrice();

        //退款金额判定 如果退款总额！=流水金额 则表明有最终几分的插值，将这个值按照优先级-》平台-》商家-》供应商 -》分销 依次加上
        //PS： 判定优先级是因为可能某个角色分的额度是0，所以需要有顺序调整。即便是平台，平台也可以选择没有佣金，不分钱
        if (!refundTotal.equals(flowPrice)) {

            // 差额 = 申请退款金额-当前退款总额 通常为正数
            Double difference = flowPrice - refundTotal;

            //按照顺序进行扣减，但是需要先判定是否大于0，这里不管怎么计算还是会有一丁点偏差，因为数据总是可能会除不尽

            if (currentRefundPriceDTO.getPlatformRefundPrice() > 0) {
                currentRefundPriceDTO.setPlatformRefundPrice(CurrencyUtil.add(currentRefundPriceDTO.getPlatformRefundPrice(), difference));
            } else if (currentRefundPriceDTO.getSellerRefundPrice() > 0) {
                currentRefundPriceDTO.setSellerRefundPrice(CurrencyUtil.add(currentRefundPriceDTO.getSellerRefundPrice(), difference));
            } else if (currentRefundPriceDTO.getSupplierRefundPrice() > 0) {
                currentRefundPriceDTO.setSupplierRefundPrice(CurrencyUtil.add(currentRefundPriceDTO.getSupplierRefundPrice(), difference));
            } else if (currentRefundPriceDTO.getDistributionRefundPrice() > 0) {
                currentRefundPriceDTO.setDistributionRefundPrice(CurrencyUtil.add(currentRefundPriceDTO.getDistributionRefundPrice(), difference));
            } else {
//                throw new ServiceException("退款金额计算错误");
            }
        }


        //将退款金额赋值到当前流水信息
        this.setSupplierRefundPrice(CurrencyUtil.add(this.supplierRefundPrice, currentRefundPriceDTO.getSupplierRefundPrice()));
        this.setSellerRefundPrice(CurrencyUtil.add(this.sellerRefundPrice, currentRefundPriceDTO.getSellerRefundPrice()));
        this.setDistributionRefundPrice(CurrencyUtil.add(this.distributionRefundPrice, currentRefundPriceDTO.getDistributionRefundPrice()));
        this.setPlatformRefundPrice(CurrencyUtil.add(this.platformRefundPrice, currentRefundPriceDTO.getPlatformRefundPrice()));


    }

    public Double getRefundPrice() {
        if (refundPrice == null) {
            refundPrice = 0D;
        }
        return refundPrice;
    }
}